﻿/***************************************************************************
	Copyright (C) 2010 RapidWebDev Organization (Author: Eunge, Legal Name: Jian Liu, Email: eunge.liu@gmail.com)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ***************************************************************************/

using System;
using System.Drawing;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using WebGridView = System.Web.UI.WebControls.GridView;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using BaoJianSoft.Common;

namespace BaoJianSoft.Web.Extensions.DynamicPages
{
	/// <summary>
	/// Simple field bound template.
	/// </summary>
	public class BoundFieldTemplate : ITemplate
	{
		private static readonly Regex regexToPickVariables = new Regex(@"\$[^\$]+\$", RegexOptions.Compiled);

		private string fieldName;
		private string bindingFormat;
		private string output;

		/// <summary>
		/// Sets/gets conditional display formatter.
		/// </summary>
		public ConditionalDisplayFormatter ConditionalDisplayFormatter { get; set; }

		/// <summary>
		/// Construct BoundField Template
		/// </summary>
		/// <param name="fieldName"></param>
		public BoundFieldTemplate(string fieldName) : this(fieldName, null) { }

		/// <summary>
		/// Construct BoundField Template
		/// </summary>
		/// <param name="fieldName"></param>
		/// <param name="bindingFormat"></param>
		public BoundFieldTemplate(string fieldName, string bindingFormat) : this(fieldName, bindingFormat, null) { }

		/// <summary>
		/// Construct BoundField Template
		/// </summary>
		/// <param name="fieldName"></param>
		/// <param name="bindingFormat"></param>
		/// <param name="output"></param>
		public BoundFieldTemplate(string fieldName, string bindingFormat, string output)
		{
			this.fieldName = fieldName;
			this.bindingFormat = bindingFormat;
			this.output = output;
		}

		/// <summary>
		/// When implemented by a class, defines the System.Web.UI.Control object that child controls and templates belong to. 
		/// These child controls are in turn defined within an inline template.
		/// </summary>
		/// <param name="container"></param>
		public void InstantiateIn(Control container)
		{
			HtmlGenericControl control = new HtmlGenericControl("div");
			control.DataBinding += new EventHandler(this.OnDataBinding);
			container.Controls.Add(control);
		}

		private void OnDataBinding(object sender, EventArgs e)
		{
			try
			{
				HtmlGenericControl control = sender as HtmlGenericControl;
				GridViewRow gridViewRow = (GridViewRow)control.NamingContainer;

				object fieldValue = ResolveFieldValue(gridViewRow.DataItem, this.fieldName, this.bindingFormat, this.output);
				string stringValue = fieldValue == null ? null : fieldValue.ToString();
				if (this.ConditionalDisplayFormatter != null)
				{
					if (this.ConditionalDisplayFormatter.Callback != null)
					{
						stringValue = this.ConditionalDisplayFormatter.Callback.Format(stringValue);
					}
					else if (this.ConditionalDisplayFormatter.Matchers != null && this.ConditionalDisplayFormatter.Matchers.Count() > 0)
					{
						string formatString = this.ConditionalDisplayFormatter.Matchers.Where(m => m.ValueToMatch == stringValue).Select(m => m.FormatString).FirstOrDefault();
						if (formatString != null) stringValue = string.Format(formatString, stringValue);
					}
				}

				control.InnerHtml = stringValue;
			}
			catch(Exception exp)
			{
				Logger.Instance(this).Warn(exp);
			}
		}

		private static object ResolveFieldValue(object dataItem, string fieldName, string bindingFormat, string output)
		{
			if(Kit.IsEmpty(output))
				return DataBinder.Eval(dataItem, fieldName, bindingFormat);

			MatchCollection matchCollection = regexToPickVariables.Matches(output);
			if (matchCollection.Count == 0) return output;

			StringBuilder returnValue = new StringBuilder();
			int lastMatchEndIndex = 0;
			for (int i = 0; i < matchCollection.Count; i++)
			{
				Match match = matchCollection[i];
				if (match.Index > lastMatchEndIndex)
				{
					string constValue = output.Substring(lastMatchEndIndex, match.Index - lastMatchEndIndex);
					returnValue.Append(constValue);
				}

				string variableName = match.Value.Substring(1, match.Value.Length - 2);
				string partialValue = DataBinder.Eval(dataItem, variableName, bindingFormat);
				returnValue.Append(partialValue);

				lastMatchEndIndex = match.Index + match.Length;

				if (i == matchCollection.Count - 1 && lastMatchEndIndex < output.Length)
				{
					returnValue.Append(output.Substring(lastMatchEndIndex));
				}
			}

			return returnValue;
		}
	}
}

